#include "string/stringmanipulations.h"

using namespace PILO::Core::String;

namespace PILO 
{
    namespace Core
    {
        namespace String 
        {
#           if defined(WIN32) || defined(WINDOWS)

#           else
            size_t _compat_mbslen(const unsigned char * mbstring)
            {
                if (mbstring == (const unsigned char *) 0) {
                    return -1;
                }
                int count = 0;
                while (*mbstring != 0) {
                    if ((*mbstring) & (1<<7)) {
                        if ((*(mbstring+1) != 0) && ((*(mbstring+1)) & (1<<7))) {
                            mbstring ++;
                        }
                    } 
                    count ++;
                    mbstring ++;
                }

                return count;
            }

            size_t _compat_mbstowcs(wchar_t *dest, const char *src, int_r n)
            {
#               if defined(HAVE_PTHREAD_H)
                mbstate_t       mbstate;  
                memset((void*)&mbstate, 0, sizeof(mbstate)); 
                return mbsrtowcs(dest, &src, n, &mbstate);
#               else
                return mbstowcs(dest, src, n);	
#               endif
            }
#           endif

            BOOL IsCharWhiteSpace(char c)
            {
                return isspace((unsigned char)c);
            }
            BOOL IsCharWhiteSpace(wchar_t wc){
                return iswspace(wc);
            }

            void* MemoryMove(void* dst, const void* src, size_t count)
            {
                ASSERT(dst != NULL);
                ASSERT(src != NULL);

#           if defined(WIN32) || defined(WINDOWS)
                memmove_s(dst,count,src, count);
#           else
                memmove(dst, src, count);
#           endif
                return dst;
            }

            TriState IsMutibyteString(const char * str, size_t len)
            {
                if (str == MC_NULLPTR_OF_(char*)) {
                    return EnumTriStateNA;
                }

                if (len == MC_INVALID_SIZE) {
                    len = strlen(str);
                }

                size_t i;

                for (i=0; i<len; i++) {
                    if (str[i] & (1<<7)) {
                        return EnumTriStateYes;
                    }
                }
                return EnumTriStateNo;
            }

            size_t StringLength(const char* strSource)
            {
                if (strSource == MC_NULLPTR_OF_(char*)) {
                    return MC_INVALID_SIZE;
                }
                return strlen(strSource);
            }
            size_t StringLength(const wchar_t* strSource)
            {
                if (strSource == MC_NULLPTR_OF_(wchar_t*)) {
                    return MC_INVALID_SIZE;
                }

                return wcslen(strSource);
            }

            size_t StringLength(const unsigned char * strSource)
            {
                if (strSource == MC_NULLPTR_OF_(unsigned char*)) {
                    return MC_INVALID_SIZE;
                }

#               if defined(WIN32) || defined(WINDOWS)
                return _mbslen(strSource);
#               else
                return _compat_mbslen(strSource);
#               endif
            }


            INT32 StringCompare(const unsigned char * str1, const unsigned char * str2,size_t length)
            {
#if             defined(WIN32) || defined(WINDOWS)
                if (IsMutibyteString((const char *)str1) == EnumTriStateYes) {
                    if (length == MC_INVALID_SIZE) {
                        return _mbscmp(str1, str2);
                    } else {
                        return _mbsncmp(str1, str2,length);
                    }

                } else {
                    if (length == MC_INVALID_SIZE) {
                        return strcmp((const char *)str1, (const char *)str2);
                    } else {
                        return strncmp((const char *)str1,(const char *)str2,length);
                    }
                }
#               else
                if (length <= 0) {
                    return strcmp((const char *)str1, (const char *)str2);
                } else {
                    return strncmp((const char *)str1,(const char *)str2,length);
                }
#               endif
            }

            INT32 StringCompare(const char * str1, const char * str2,size_t length)
            {
                if (length == MC_INVALID_SIZE) {
                    return strcmp(str1, str2);
                } else {
                    return strncmp(str1,str2,length);
                }

            }
            INT32 StringCompare(const wchar_t * str1, const wchar_t * str2,size_t length)
            {
                if (length == MC_INVALID_SIZE) {
                    return wcscmp(str1, str2);
                } else {
                    return wcsncmp(str1,str2,length);
                }
            }

            INT32 StringCaseIgnoredCompare(const unsigned char * str1, const unsigned char * str2, size_t length)
            {
#               if defined(WIN32) || defined(WINDOWS)
                if (IsMutibyteString((const char *)str1) == EnumTriStateYes) {
                    if (length == MC_INVALID_SIZE) {
                        return _mbsicmp(str1, str2);
                    } else {
                        return _mbsnicmp(str1, str2,length);
                    }

                } else {
                    if (length == MC_INVALID_SIZE) {
                        return _stricmp((const char *)str1, (const char *)str2);
                    } else {
                        return _strnicmp((const char *)str1,(const char *)str2,length);
                    }
                }
#               else
                if (length == MC_INVALID_SIZE) {
                    return _stricmp((const char *)str1, (const char *)str2);
                } else {
                    return _strnicmp((const char *)str1,(const char *)str2,length);
                }
#               endif
            }
            INT32 StringCaseIgnoredCompare(const char * str1, const char * str2,size_t length)
            {
                if (length == MC_INVALID_SIZE) {
                    return _stricmp(str1, str2);
                } else {
                    return _strnicmp(str1,str2,length);
                }
            }
            INT32 StringCaseIgnoredCompare(const wchar_t * str1, const wchar_t * str2,size_t length)
            {
                if (length == MC_INVALID_SIZE) {
                    return _wcsicmp(str1, str2);
                } else {
                    return _wcsnicmp(str1,str2,length);
                }
            }

        } /* String */ 

    }    
} /* PILO */

